package reesoft.idgenerator.service;

import reesoft.common.code.ErrorCode;
import reesoft.common.util.StringUtil;
import reesoft.idgenerator.IdGenerateException;
import reesoft.idgenerator.IdGeneratorErrorCode;
import reesoft.idgenerator.entity.IdRange;
import reesoft.idgenerator.service.idstore.IdStore;
import reesoft.idgenerator.service.idstore.IdStoreFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

/**
 * 序号生成服务类
 *
 * Created by reesoft on 2017-08-28
 */
@Service
public class IdGenerateService
{
    /**
     * 序号名称与序号生成对象的映射表
     */
    private static final ConcurrentMap<String, IdGenerator> idGeneratorHashMap = new ConcurrentHashMap<>();

    /**
     * 批量分配序号的数量
     */
    private static final long BATCH_ASSIGN_AMOUNT = 1000;

    /**
     * 序号存储工厂
     */
    @Autowired
    private IdStoreFactory idStoreFactory;

    /**
     * 注册一个序号
     *
     * @param name 序号的名称
     * @throws IdGenerateException
     */
    public void registerId(String name) throws IdGenerateException
    {
        if (StringUtil.isBlank(name))
        {
            throw new IdGenerateException(ErrorCode.INVALID_PARAMETER);
        }

        IdGenerator idGenerator = getIdGenerator(name, true);

        idGenerator.init(name);
    }

    /**
     * 注册一个序号
     *
     * @param name      序号的名称
     * @param initValue 初始值
     * @param maxValue  最大值
     * @throws IdGenerateException
     */
    public void registerId(String name, long initValue, long maxValue) throws IdGenerateException
    {
        if (StringUtil.isBlank(name))
        {
            throw new IdGenerateException(ErrorCode.INVALID_PARAMETER);
        }

        IdGenerator idGenerator = getIdGenerator(name, true);

        idGenerator.init(name, initValue, maxValue);
    }

    /**
     * 查询序号是否已注册
     *
     * @param name 序号的名称
     * @throws IdGenerateException
     */
    public boolean check(String name) throws IdGenerateException
    {
        if (StringUtil.isBlank(name))
        {
            return false;
        }

        IdStore idStore = idStoreFactory.getIdStore();

        if (idStore == null)
        {
            return false;
        }

        return idStore.check(name);
    }

    /**
     * 获取下个可用的序号
     *
     * @param name 序号的名称
     * @return 下个可用的序号
     * @throws IdGenerateException
     */
    public long next(String name) throws IdGenerateException
    {
        if (StringUtil.isBlank(name))
        {
            throw new IdGenerateException(ErrorCode.INVALID_PARAMETER);
        }

        IdGenerator idGenerator = getIdGenerator(name);

        if (idGenerator == null)
        {
            throw new IdGenerateException(IdGeneratorErrorCode.ID_NOT_REGISTERED);
        }

        return idGenerator.next();
    }

    /**
     * 获取下一批序号
     *
     * @param amount 数量
     * @return 返回序号批次中第一个序号和可用序号数量，数量可能会小于请求的数量
     * @throws IdGenerateException
     */
    public synchronized IdRange next(String name, long amount) throws IdGenerateException
    {
        if (StringUtil.isBlank(name)
                || amount <= 0)
        {
            throw new IdGenerateException(ErrorCode.INVALID_PARAMETER);
        }

        IdGenerator idGenerator = getIdGenerator(name);

        if (idGenerator == null)
        {
            throw new IdGenerateException(IdGeneratorErrorCode.ID_NOT_REGISTERED);
        }

        return idGenerator.next(amount);
    }

    /**
     * 获取序号生成对象
     *
     * @param name 序号的名称
     * @param create 是否初始化序号存储空间
     * @return 序号生成对象
     * @throws IdGenerateException
     */
    private IdGenerator getIdGenerator(String name, boolean create) throws IdGenerateException
    {
        IdGenerator idGenerator = idGeneratorHashMap.get(name);

        if (idGenerator == null)
        {
            IdStore idStore = idStoreFactory.getIdStore();

            if (idStore == null)
            {
                throw new IdGenerateException("Failed to create ID store");
            }

            // 如果要注册序号，或序号已注册，自动创建序号生成对象
            if (create || idStore.check(name))
            {
                if (create)
                {
                    idStore.init(name);
                }

                idGenerator = new IdGenerator(name, idStore, BATCH_ASSIGN_AMOUNT);
                idGeneratorHashMap.putIfAbsent(name, idGenerator);
            }
        }

        return idGenerator;
    }

    /**
     * 获取序号生成对象
     *
     * @param name 序号的名称
     * @return 序号生成对象
     * @throws IdGenerateException
     */
    private IdGenerator getIdGenerator(String name) throws IdGenerateException
    {
        return getIdGenerator(name, false);
    }
}
